//自定义协议
#pragma once
#include<iostream>
#include<string>
#include<memory>
#include<jsoncpp/json/json.h>     //引入json
#include"Socket.hpp"

//只有协议最清楚该如何读写
using namespace SocketModule;

//约定好各个字段的含义  本质就是约定好协议

//实现一个自定义网络版本计算器
//client 到 server   时发送请求时发送的报文
class Request
{
public:
    Request()
    {}

//有参构造
    Request(int x,int y,char oper)
        :_x(x),
        _y(y),
        _oper(oper)    
    {}

//request  提供序列化   完成序列化
    std::string Serialize(int x,int y,char port)
    {
        //把表达式转化成为   字符串
        //序列化处理
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        
        Json::FastWriter writer;
        std::string s = writer.write(root); 
        
        return s;
    }

//提供反序列化   接收方收到字符串风格请求   反向转成结构化
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;

        bool ok = reader.parse(in,root);    //反序列化  调 Json::Reader 对象的parse函数
        if(ok)
        {
            _x = root["x"].asInt();     //用键值获取结构化数据
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }

    ~Request(){}

private:
    int _x;
    int _y;
    char _oper;    //操作符   + - * / %        操作形式  _x _oper _y  ---->  10 + 20  
};


//协议(基于TCP的)需要解决两个问题：
    //1.request 和 response 必须得有序列化和反序列化功能
    //2.必须保证  读取的时候  读到完整的请求（TCP需要考虑，UDP不需要--->本就是面向数据报）

//如何做序列化和反序列化：
    //1.自己定制（在Serialize 进行用空格作为分隔符  在Deserialize中用空作为分隔符再分开）  不具备很好的扩展性
    //2.使用现成的方案 ---> 使用json ---> jsoncpp库(用这个库进行合法序列化)

//server -> client
class Response
{
public:
    Response(){}

    Response(int result,int code)
        :_result(result),
        _code(code)
    {}

//对于Response  也要提供一组序列反序列化
    std::string Serialize()
    {
        //自己进行写： _x=10,_y=20,_oper='+'
        //"10" "20" '+' ---> 以空格作为分隔符
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        return writer.write(root);
    }

    bool Deserialize(std::string &in)
    {
        //反序列化 也是"10" "20" '+' 以空格作为分隔符    find查空格查到就substr
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in,root);
        if(ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ok;
    }

    ~Response(){}

private:
    int _result;   //运算结果（只有运算结果  无法区分清楚应答是计算结果，还是异常值）
    int _code;     //0：success     1 2 3 4 ---> 不同运算异常情况    只有code是0  结果才可信
};



const std::string sep = "\r\n";

class Protocol
{
public:
    Protocol()
    {}
    
//添加报头和解析报头的方法
    std::string Encode(const std::string jsonstr)
    {
        //加上长度和特殊字符
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep;    //应用层封装报头
    }

//专门的引用   &package
//可能会收到: 
//5
//50
//50\r
//50\r\n{"x":10,"
//50\r\n{"x":10,"y":20,"oper":'+'}\r\n 
//50\r\n{"x":10,"y":20,"oper":'+'}\r\n50\r\n{"x":10,"y":20,"ope
//...........
    //1.判断报文完整性
    //2.如果包含了完整的请求，就提取出来并从缓冲区中移除他，方便处理下一个
    bool Decode(std::string &buffer,std::string *package)
    {
        ssize_t pos = buffer.find(sep);
    
    //这种是只读到数字   没有后续内容   调用方继续从内核中读取数据
        if(pos == std::string::npos)   return false;
        std::string package_len_str = buffer.substr(0,pos);     //从开头处  提取pos长读
        int package_len_int = std::stoi(package_len_str);       //字符串转整数
        
    //到这  buffer一定有长度，但是不一定有完整的报文
        int target_len = package_len_str.size() + package_len_int + 2 * sep.size(); 
        if(buffer.size() < target_len)    //这是不可能有有效报文
            return false;

    // buffer 里一定至少有一个完整的报文
        *package = buffer.substr(pos+sep.size(),package_len_int);    //提取json串
        buffer.erase(0,target_len);    //把整个报文给移除
        
        return true;   
    }



//获取请求
    void GetRequest(std::shared_ptr<Socket> &sock,InetAddr &client)  //协议怎么从网络中读取数据   从套接字中读，客户端是谁
    {
        //读取
        
        


    }

    ~Protocol()
    {}

private:
    //这里用的是多进程   所以可以加上Request  Response    如果未来想多线程多进程都能使用那就把这两个成员屏蔽   后面以临时变量用
        // Request _req;     //请求
        // Response _resp;   //应答
};

